package com.cskaoyan.javase.object.hashcode5;

/**
 * @description: hashCode()方法
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 方法的声明：
 * public int hashCode()
 * - 语法
 *   对象名.hashCode()
 * - 通过一个哈希（散列）函数，返回该对象的哈希（码）值
 * - 支持此方法是为了提高哈希表的性能（主要是集合体系中用）
 * 哈希表本身是一种数据结构，key-value 集合都是装对象的 通过哈希方法算出key的值
 *
 * Object类中的哈希方法：
 *     public native int hashCode();
 * native：本地的
 * jvm当中的本地方法栈是给本地方法用的，而Java当中使用native修饰的方法就是本地方法
 * 本地方法实际上不是Java方法，而是调用C/C++的方法，这里我们不关心这个方法到底咋实现的
 *
 * 实际上，由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。（这一般是通过将该对象的内部地址转换成一个整数来实现的，但是 Java编程语言不需要这种实现技巧。）
 * Object类中的hashCode()方法的返回值可以认为就是该对象的内存地址值（十进制的）
 * 打印对象名看到的是对象的十六进制地址值
 *
 * hashCode方法和equals方法一定是同对出现，equals方法实际上重写后是用成员变量的取值去比较的
 * hashCode方法也要类似重写：
 * hashCode 的常规协定是：
 * 在 Java 应用程序执行期间，在对同一对象多次调用 hashCode 方法时，必须一致地返回相同的整数，前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行，该整数无需保持一致。
 * 若equals方法是用成员变量的取值来判定的，那么hashCode也要一样用成员变量的取值判定
 *
 * 如果根据 equals(Object) 方法，两个对象是相等的，那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
 * equals()方法是家中的大哥，equals(Object)认为两个对象相等，哈希方法必须要返回同样的哈希值
 *
 * 如果根据 equals(java.lang.Object) 方法，两个对象不相等，那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是，程序员应该意识到，为不相等的对象生成不同整数结果可以提高哈希表的性能。
 * 哈希冲突很正常，我也允许你有哈希冲突，但是作为一名优秀的程序员，应该致力于解决哈希冲突，设计更好的哈希算法
 * 明确知道更少的哈希冲突，可以让哈希表的性能更高
 * 我们应该相信光，永远追求美好的东西
 *
 *具体的哈希方法实现，是属于算法范畴的
 * 你要相信如果你不是专门研究算法的，你写出来的是赶不上IDEA给你生成的
 *以后的绝大多数开发中，使用idea自动生成的就足够
 *
 */
public class Demo {
    public static void main(String[] args) {
        Student s = new Student(1,"1");
        Student s2 = new Student(1,"1");
        Student s3 = new Student(10,"1");
        System.out.println(s.equals(s2));
        System.out.println(s.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());
        System.out.println(s.hashCode() == s2.hashCode()); //false

    }
}
class Student{
    int age;
    String name;

    public Student() {
    }

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    //重写一下哈希方法 1997


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = age;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }
}
